package com.dal.module.account;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import com.dal.manager.ActivateCodeManager;

import org.apache.commons.collections4.MapUtils;
import org.bean.GameServerInfo;
import org.bean.InterceptInfoDTO;
import org.cache.InterceptMappingCache;
import org.constant.InterceptConstant;
import org.error.LoginErrorCode;

import com.dal.cache.GameServerInfoCache;
import com.dal.cache.TokenCache;
import com.dal.constant.AccountCreatorEnum;
import com.dal.constant.ParamCheckerEnum;
import com.dal.constant.ParamKey;
import com.dal.constant.PlatformVerifyerEnum;
import com.dal.db.bean.Account;
import com.dal.db.bean.ActivateCode;
import com.dal.db.bean.Channel;
import com.dal.db.bean.ChannelApp;
import com.dal.db.cache.AccountCache;
import com.dal.db.cache.ActivateCodeCache;
import com.dal.db.cache.ChannelAppCache;
import com.dal.db.cache.ChannelCache;
import com.dal.module.account.account_creator.AccountCreator;
import com.dal.module.base.BaseController;
import com.dal.module.game_server.GameServerController;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.sojoys.artifact.annotation.IController;
import com.sojoys.artifact.constant.ServerStatusEnum;
import com.sojoys.artifact.tools.ToolError;
import com.sojoys.artifact.tools.ToolMap;
import com.xiaoleilu.hutool.crypto.SecureUtil;
import com.xiaoleilu.hutool.log.Log;
import com.xiaoleilu.hutool.log.LogFactory;

import org.utils.RemoteUtil;

/**
 * @author : DengYing
 * @CreateDate : 2017年6月21日 上午10:40:34
 * @Description ：Please describe this document
 */
@IController("/account")
@SuppressWarnings({"rawtypes", "unchecked"})
public class AccountController extends BaseController {

    static Log log = LogFactory.get(AccountController.class);

    /**
     * 登陆
     */
    public void login() {
        Map param = Maps.newHashMap();
        String channelTag = getPara(ParamKey.CHANNEL_TAG);
        String channelAppKey = getPara(ParamKey.CHANNEL_APP_KEY);
        String clientVersion = getPara(ParamKey.CLIENT_VERSION);
        Channel channel = ChannelCache.me().getByTag(channelTag);
        
        ToolError.isAndTrue(LoginErrorCode.NOT_FOND_CHANNEL,"渠道错误", channel == null);
        
        ChannelApp channelApp = ChannelAppCache.me().getByChannelIdAppKey(channel.getId(), channelAppKey);
        ToolError.isAndTrue(LoginErrorCode.NOT_FOND_CHANNEL_APP,"渠道包不存在", channelApp == null);
             
        // 校验客户端版本
		checkClientVersion(clientVersion, channelApp);
            
        // 渠道检查
        ParamCheckerEnum.check(channelTag, this, param);

        // 账号校验
        PlatformVerifyerEnum.verify(channelApp, param);

        // 获取或新建账号
        Account account = getAccount(channelApp,param);

        // 更新账号信息
        updateAccount(account,channelApp,param);


        if (isAccountFreeze(account)){
            return;
        }
        // 获取社交服务器维护状态
        int status = RemoteUtil.socialSync().getStatus();
        ToolError.isAndTrue(LoginErrorCode.STATE_AEGIS,"服务器维护中", !account.isAdmin() && status != ServerStatusEnum.RUNNING.getCode());

        // 管理员不受开服时间限制
        if (!account.isAdmin() && channelApp.getOpenServerDate().after(new Date())) {
        	Map<String, Object> map = new HashMap<>();
			map.put(ParamKey.OPEN_SERVER_DATE, channelApp.getOpenServerDate().getTime());
			renderSuccess(map, "");
		}else {
			GameServerInfo gs = GameServerInfoCache.getByServerId(account.getGameServerId());

	        // 如果账号没有激活
	        if (!account.isActivate()) {
	            Map<String, String> map = new HashMap<>();
	            map.put(ParamKey.NEED_ACTIVATE, "1");
	            renderSuccess(map, "");
	        } else {
	            // 生成并缓存token
	            String token = getToken(account);
	            Map<String, String> map = new HashMap<>();
	            map.put(ParamKey.TOKEN, token);
	            map.put(ParamKey.GAME_SERVER_IP, gs.getRemoteHost());
	            map.put(ParamKey.GAME_SERVER_PORT, gs.getSocketPort() + "");
	            renderSuccess(map, "");
	        }
		}
    }

    public void adminLogin(){
        int pid = Integer.valueOf(getPara(ParamKey.PID));
        String uid = RemoteUtil.socialSync().getUid(pid);
        ToolError.isAndTrue(LoginErrorCode.PID_IS_WRONG,"pid错误", uid == null);

        InterceptInfoDTO dto = InterceptMappingCache.checkIntercept(InterceptConstant.INTERCEPT_TYPE_ACCOUNT_ID, uid);

        ToolError.isAndTrue(LoginErrorCode.NOT_FREEZE,"未冻结，不能登录", dto == null);

        Account account = AccountCache.me().getById(uid);
        GameServerInfo gs = GameServerInfoCache.getByServerId(account.getGameServerId());

        String token = getToken(account);
        Map<String, String> map = new HashMap<>();
        map.put(ParamKey.TOKEN, token);
        map.put(ParamKey.GAME_SERVER_IP, gs.getRemoteHost());
        map.put(ParamKey.GAME_SERVER_PORT, gs.getSocketPort() + "");
        renderSuccess(map, "");
    }

    /**
     * 更新账号信息
     * @param account
     * @param param
     */
    private void updateAccount(Account account,ChannelApp channelApp,Map param) {
//    	account.setGameServerId(ToolMap.getString(ParamKey.SERVER_ID, param,""));
        account.setOsName(ToolMap.getString(ParamKey.OS_NAME, param,""));
        account.setOsVersion(ToolMap.getString(ParamKey.OS_VERSION, param,""));
        account.setDeviceId(ToolMap.getString(ParamKey.DEVICE_ID, param,""));
        account.setDeviceToken(ToolMap.getString(ParamKey.DEVICE_TOKEN, param,""));
        account.setDeviceName(ToolMap.getString(ParamKey.DEVICE_NAME, param,""));
//        account.setChannelId(channelApp.getChannelId());
//        account.setChannelAppId(channelApp.getId());
        account.setSdk(ToolMap.getString(ParamKey.SDK, param,""));
        account.setSdkVersion(ToolMap.getString(ParamKey.SDK_VERSION, param,""));
        account.setIp(ToolMap.getString(ParamKey.CLIENT_IP, param,""));
        account.setPhoneNumber(MapUtils.getString(param, ParamKey.MOBILE,""));
        account.setClientVersion(ToolMap.getString(ParamKey.CLIENT_VERSION, param,""));
        account.setLanguage(ToolMap.getString(ParamKey.LANGUAGE, param,"zh_CN"));
        account.update();
	}

	private String getToken(Account account) {
        String token = UUID.randomUUID().toString();
        TokenCache.addCache(account.getId(), token);
        return token;
    }

    public void checkActivateCode() {
        String accountId = getPara(ParamKey.ACCOUNT_ID);
        String channelTag = getPara(ParamKey.CHANNEL_TAG);
        String channelAppKey = getPara(ParamKey.CHANNEL_APP_KEY);
        String clientVersion = getPara(ParamKey.CLIENT_VERSION);
        Channel channel = ChannelCache.me().getByTag(channelTag);
        
        ToolError.isAndTrue(LoginErrorCode.NOT_FOND_CHANNEL,"渠道错误", channel == null);
        
        ChannelApp channelApp = ChannelAppCache.me().getByChannelIdAppKey(channel.getId(), channelAppKey); 
        
        ToolError.isAndTrue(LoginErrorCode.NOT_FOND_CHANNEL_APP,"渠道包不存在", channelApp == null);
        
        ToolError.isAndTrue(LoginErrorCode.MISS_ACCOUNT_ID, "缺少参数:accountId", accountId == null || "".equals(accountId));
        
        Account account = AccountCache.me().getByAccountIdChannelId(accountId,channelApp.getChannelId());
        
        ToolError.isAndTrue(LoginErrorCode.NOT_FIND_ACCOUNT, "没有找到账号", account == null);
        
        String activateKey = getPara(ParamKey.ACTIVATE_KEY);
        // 验证激活码
        ActivateCodeManager.checkAndUpdateActivateCode(activateKey,account.getId());
        account.setActivate(true);
        account.update();

        // 生成并缓存token
        String token = getToken(account);

        GameServerInfo gs = GameServerInfoCache.getByServerId(account.getGameServerId());

        Map<String, String> map = new HashMap<>();
        map.put(ParamKey.TOKEN, token);
        map.put(ParamKey.GAME_SERVER_IP, gs.getRemoteHost());
        map.put(ParamKey.GAME_SERVER_PORT, gs.getSocketPort() + "");
        renderSuccess(map, "");
    }

    /**
     * 获取激活码
     */
    public void getActivateCode() {
        int num = getParaToInt(ParamKey.NUM, 1);
        if (num > 1000)
            num = 1000;
        List<String> codeList = Lists.newArrayList();
        for (int i = 0; i < num; i++) {
            ActivateCode activateCode = new ActivateCode();
            String code = createCode();
            if (code == null)
                continue;
            activateCode.setInvitationCode(code);
            ActivateCodeCache.me().insert(activateCode);
            codeList.add(code);
        }
        renderSuccess(codeList, "");
    }

    private static String[] chars = new String[]{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D",
            "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y",
            "Z"};

    /**
     * 生成激活码字符串（8位字母及数字组合）
     *
     * @return
     */
    private static String generateShortUuid() {
        StringBuffer shortBuffer = new StringBuffer();
        String uuid = UUID.randomUUID().toString().replace("-", "");
        for (int i = 0; i < 8; i++) {
            String str = uuid.substring(i * 4, i * 4 + 4);
            int x = Integer.parseInt(str, 16);
            shortBuffer.append(chars[x % 36]);
        }
        return shortBuffer.toString();
    }

    /**
     * 生成激活码
     */
    private String createCode() {
        int i = 0;
        while (i < 3) {
            String code = generateShortUuid().toLowerCase();
            // 如果缓存中已经有该字符串了，就重新生成一个字符串，如果生成的三次字符串都存在，则不再继续生成
            if (ActivateCodeCache.me().getByInvitationCode(code) == null)
                return code;
            i++;
        }
        return null;
    }

    /**
     * 获取账户（账号id、appId），如果没有就新建一个
     */
    private Account getAccount(ChannelApp channelApp,Map param) {
        String accountId = (String) param.get(ParamKey.ACCOUNT_ID);
        Account account = AccountCache.me().getByAccountIdChannelId(accountId, channelApp.getChannelId());
        
        // 账号不存在则新建一个
        if (account == null) {
            AccountCreator creator = AccountCreatorEnum.getAccountCreator(channelApp);
            // 获取推荐服务器
            GameServerInfo gs = GameServerController.me().getRecommendServer();
            param.put(ParamKey.SERVER_ID, gs.getId());
            account = creator.create(channelApp,param);
        } else {
            if (channelApp.isNeedPassword()){
            	String password = ToolMap.getString(ParamKey.PASSWORD, param,"");
            	password = SecureUtil.md5(password);
                ToolError.isAndTrue(LoginErrorCode.PASSWORD_ERR, "密码错误", !account.getPassword().equals(password));
            }
        }
        return account;
    }


    private boolean isAccountFreeze(Account account) {
        InterceptInfoDTO dto = InterceptMappingCache.checkIntercept(InterceptConstant.INTERCEPT_TYPE_ACCOUNT_ID, account.getId());
        if (dto != null) {
            Map<String, String> map = new HashMap<>();
            map.put(ParamKey.FREEZE_DEADLINE, ((int) (dto.getDeadLine().getTime() / 1000)) + "");
            renderSuccess(map, "");
            return true;
        }
        return false;
    }


    /**
     * 校验客户端版本
     *
     * @param param   参数
     * @param account 账号
     */
    private void checkClientVersion(String version, ChannelApp app) {
    	String minVersion = app.getMinClientVer();
    	String maxVersion = app.getMaxClientVer();
    	
    	ToolError.isAndTrue(LoginErrorCode.CLIENT_VERSION_ERR,compareVersion(version, minVersion) < 0);
    	
    	ToolError.isAndTrue(LoginErrorCode.CLIENT_VERSION_ERR,compareVersion(version, maxVersion) > 0);
    }

    /** 
     * 比较版本号的大小,前者大则返回一个正数,后者大返回一个负数,相等则返回0 
     * @param version1 
     * @param version2 
     * @return 
     */  
    public static int compareVersion(String version1, String version2){  
        String[] versionArray1 = version1.split("\\.");//注意此处为正则匹配，不能用.；  
        String[] versionArray2 = version2.split("\\.");  
        int idx = 0;  
        int minLength = Math.min(versionArray1.length, versionArray2.length);//取最小长度值  
        int diff = 0;  
        while (idx < minLength  
                && (diff = versionArray1[idx].length() - versionArray2[idx].length()) == 0//先比较长度  
                && (diff = versionArray1[idx].compareTo(versionArray2[idx])) == 0) {//再比较字符  
            ++idx;  
        }  
        //如果已经分出大小，则直接返回，如果未分出大小，则再比较位数，有子版本的为大；  
        diff = (diff != 0) ? diff : versionArray1.length - versionArray2.length;  
        return diff;  
    }  
    
    public static void main(String[] args) {
		System.out.println(compareVersion("1.0.00", "1.0.00"));
	}
}
